/**
 * @public
 * @param {String|XMLDocument} xmlDoc XMLDocument对象或者XML字符串
 */
function Template(xmlDoc)
{
	this.taglib = {};

	this.putTaglib(new DefaultTag(), "*");
	this.putTaglib(new XHTMLTag());
	this.putTaglib(new CoreTag());

	if (typeof xmlDoc == "string")
	{
		this.doc = Template.loadDoc(xmlDoc);
	}
	else if (xmlDoc != null)
	{
		this.doc = xmlDoc;
	}
}

/**
 * 加载文档
 * @param {string} value xml url or xml string
 */
Template.loadDoc = function(value)
{
	if (! /^[\s\ufeff]*</.test(value))
	{
		var doc = new Request(value).send().getXML(true);

		if (typeof doc != "string")
		{
			return doc;
		}
		else
		{
			value = doc;
		}
	}
	return new DOMParser().parseFromString(value, "text/xml");
}

var $p = Template.prototype;
/**
 * 添加Tag库
 * @public
 * @param {Object} tl Taglib
 * @param {String} ns 名称
 * @id Template.prototype.putTaglib
 */
$p.putTaglib = function(tl, ns)
{
	this.taglib[ns || tl.namespaceURI] = tl;
}
/**
 * 视图描绘
 * @public
 * @param data {Object|OutputContext} 数据集合
 * @param out {Array|Writer|Document} 数组 或者 输出接口至少需要一个成员函数 write(string)
 * @id Template.prototype.render
 */
$p.render = function(data, out)
{
	var out2
		, context = out != null ? new OutputContext(data, out) : data instanceof OutputContext ? data : new OutputContext(data, out2 = []);

	context.template = this;
	var ctl = context.taglib;
	context.taglib = new StackMap(this.taglib);

	for (var n in ctl)
	{
		context.taglib[n] = ctl[n];
	}
	context.output(this.doc);

	if (out2)
	{
		return out2.join("");
	}
}

/**
 * 值栈对象
 */
function ValueStack(data)
{
	this.context = data;
	this.stack = [];
}

$p = ValueStack.prototype;
/**
 * 压入新的上下文根
 */
$p.push = function(data)
{
	this.stack.push(this.context);
	this.context = new StackMap(this.context);

	for (var n in data)
	{
		this.context[n] = data[n];
	}
}
/**
 * 弹出顶层上下文根
 */
$p.pop = function()
{
	this.context = this.stack.pop();
}
/**
 * 在上下文对象上获取一个变量
 */
$p.setVariable = function(id, value)
{
	this.context[id] = value;
}
/**
 * å¨ä¸ä¸æå¯¹è±¡ä¸è·åä¸ä¸ªåé
 */
$p.getVariable = function(id)
{
	return this.context[id];
}
/**
 * 输出上下文对象
 * @protected
 * @param data <Object> 数据集合
 * @param out <Writer|Document> 输出接口 至少需要一个成员函数 write(string)
 */
function OutputContext(data, out)
{
	if (data == null)
	{
		data = {};
	}

	this.taglib = {};

	this.valueStack = new ValueStack(data);
	this.out = out;

	if (out instanceof Array)
	{
		this.print = this.write = arrayWrite;
	}
	else if (out.writeln)
	{
		this.writeln = this.println = nativeWriteln;
	}
	this.depth = 0;
}

$p = OutputContext.prototype;
/**
 * @public
 */
$p.putTaglib = Template.prototype.putTaglib;
/**
 * @public
 */
$p.print = $p.write = function(str)
{
	this.out.write(str);
}

/**
 * @public
 */
$p.writeln = $p.println = function(str)
{
	this.print(str);
	this.print("\r\n");
}
/**
 * @private
 */
function nativeWriteln(str)
{
	this.out.writeln(str);
}

function arrayWrite(str)
{
	this.out.push(str);
}

/**
 * @private
 */
$p.printIndent = function(str)
{
	return;
	this.out.write("\r\n");

	for (var i = this.depth - 1; i >= 0; i++)
	{
		this.out.write("  ");
	}
}
/**
 * 计算表达式
 * @protected
 */
$p.evalExpression = function(el, showError)
{
	try
	{
		with (this.valueStack.context)
		{
			return eval(el);
		}
	}
	catch (e)
	{
		return this.processException(e);
	}
}
/**
 * 处理表达式计算时发生的异常
 * @protected
 * @param <Error> e 异常对象
 * @return <string> 异常后显示的字符串
 */
$p.processException = function(e)
{
	$log.debug("expression eval error:", e);
	return "";
}
/**
 * 计算boolean值
 * @protected
 */
$p.evalBoolean = function(str)
{
	if (str)
	{
		switch (str.toLowerCase())
		{
			case "true":
				return true;

			case "false":
				return false;
		}

		try
		{
			str = this.evalText(str);

			if (str == "" || (str.toLowerCase()) == "false")
			{
				return false;
			}
			else
			{
				return true;
			}
		}
		catch (e)
		{
			return null;
		}
	}
	else
	{
		return null;
	}
}
/**
 * 计算带表达式的字符块
 * @protected
 * @param <string>str 需要计算的字符块
 */
$p.evalText = function(str)
{
	if (! str)
	{
		return str;
	}

	var k = 0
		, result = "";

	while (true)
	{
		var i = str.indexOf("${", k);

		while (str.charAt(i - 1) == "\\")
		{
			result += str.substring(k, i - 1);
			k = i;
			i = str.indexOf("${", k + 1);
		}

		if (i >= 0)
		{
			var j = str.indexOf("}", i);
			var x = str.indexOf("{", i + 2);

			if (x > i && x < j)
			{
				for (var d = 1, j = i + 2; j < str.length; j++)
				{
					var c = str.charAt(j);

					if (c == "'" || c == '"')
					{ //跳过字符串
						while (j < str.length)
						{
							j = str.indexOf(c, j + 1);

							for (var n = j - 1; str.charAt(n) == "\\"; n--);

							if ((j - n) % 2 == 1)
							{
								break;
							}
						}
					}
					else if (c == "{")
					{
						d++;
					}
					else if (c == "}")
					{
						d--;

						if (d == 0)
						{
							break;
						}
					}
				}
			}

			if (i == 0 && j == (str.length - 1))
			{
				var el = str.substring(i + 2, j);
				return this.evalExpression(el);
			}

			if (j > 0)
			{
				var el = str.substring(i + 2, j);

				if (str[i - 1] == "!")
				{
					result += str.substring(k, i - 1);
				}
				else
				{
					result += str.substring(k, i);
				}

				try
				{
					result += this.evalExpression(el);
				}
				catch (e)
				{
				//TODO:
				}
				finally
				{
					k = j + 1;
				//firefox bug for function toString
				//continue;
				}
				continue;
			}
			else
			{
				result += str.substring(k, str.length);
				break;
			}
		}
		else
		{
			result += str.substring(k, str.length);
			break;
		}
	}
	return result;
};

/**
 * 编码 xml 字符节点
 * @private
 * @param {String} str	xml字符串
 */
$p.encodeText = function(str)
{
	return str ? str.toString().replace(/</g, "&lt;").replace(/>/g, "&gt;")
	//.replace(/&/g,"&amp;")
	: "";
};
/**
 * 编码 xml 属性
 * @private
 */
$p.encodeAttribute = function(str)
{
	return str ? str.toString().replace(/</g, "&lt;").replace(/>/g, "&gt;")
	//.replace(/&/g,"&amp;")
	: "";
};

/**
 * 获取指定名称的Tag对象
 * @private
 */
$p.getTaglib = function(ns)
{
	return ns ? this.taglib[ns] || this.taglib["*"] : this.taglib["*"];
}
/**
 * 分发节点输出处理
 * @private
 */
$p.output = function(node)
{
	if (node == null)
	{
		return;
	}
	var taglib = this.getTaglib(node.namespaceURI);

	switch (node.nodeType)
	{
		case 1: //NODE_ELEMENT
			taglib.Element(this, node);
			break;

		case 3: //NODE_TEXT
			taglib.Text(this, node);
			break;

		case 4: //NODE_CDATA_SECTION
			taglib.CDATASection(this, node);
			break;

		case 5: //NODE_ENTITY_REFERENCE
			this.EntityReference(this, node);
			break;

		case 6: //NODE_ENTITY
			taglib.Entity(this, node);
			break;

		case 7: //NODE_PROCESSING_INSTRUCTION
			taglib.ProcessingInstruction(this, node);
			break;

		case 8: //NODE_COMMENT
			taglib.Comment(this, node);
			break;

		case 9: //NODE_DOCUMENT
			taglib.Document(this, node);
			break;

		case 10: //NODE_DOCUMENT_TYPE
			taglib.DocumentType(this, node);
			break;

		case 11: //NODE_DOCUMENT_FRAGMENT
			taglib.DocumentFragment(this, node);
			break;

		case 12: //NODE_NOTATION
			taglib.Notation(this, node);
			break;

		case 2: //NODE_ATTRIBUTE
			taglib.Attribute(this, node);
			break;

		default:
			this.println("<!-- ERROR UNKNOW nodeType:" + node.nodeType + "-->")
	}
};

$p = null;

/**
 * 栈表
 * @public 
 * @constructor
 */
function StackMap(p)
{
	if(p)
		return p;
	function c()
	{
	}
	c.prototype = p;
	return new c();
}